/**
 * 1992 - 2015
 */
package com.tengtong.duang.commons.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

/**
 * Class 工具类
 * 
 * @author jai
 *
 */
public class ClassUtils {

	/** Suffix for array class names: "[]" */
	public static final String ARRAY_SUFFIX = "[]";
	
	/** Prefix for internal array class names: "[" */
	private static final String INTERNAL_ARRAY_PREFIX = "[";
	
	/** Prefix for internal non-primitive array class names: "[L" */
	private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
	
	/** The ".class" file suffix */
	public static final String CLASS_FILE_SUFFIX = ".class";
	
	/** The package separator character '.' */
	public static final char PACKAGE_SEPARATOR = '.';
	
	/**
	 * Map with primitive(基础类型) type name as key and corresponding primitive
	 * type as value, for example: "int" -> "int.class".
	 */
	private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<String, Class<?>>(32);

	/**
	 * Map with common "java.lang" class name as key and corresponding Class as value.
	 * Primarily for efficient deserialization of remote invocations.
	 */
	private static final Map<String, Class<?>> commonClassCache = new HashMap<String, Class<?>>(32);	

	private static final Set<Class<?>> baseClassCache = new HashSet<Class<?>>(32);	
	
	public static final Map<Class<?>, Class<?>> primitiveTypeNameSet = new HashMap<Class<?>, Class<?>>(){{
		put(int.class, Integer.class);
		put(short.class, Short.class);
		put(long.class, Long.class);
		put(double.class, Double.class);
		put(float.class, Float.class);
		put(byte.class, Byte.class);
		put(char.class, Character.class);
	}};
	
	public static final Set<Class<?>> primitiveWrapperTypeNameSet = new HashSet<Class<?>>(){{
		add(Integer.class);
		add(Short.class);
		add(Long.class);
		add(Double.class);
		add(Float.class);
		add(Byte.class);
		add(Character.class);
		add(BigDecimal.class);
		add(BigInteger.class);
		add(Number.class);
	}};
	
	static{
		baseClassCache.add(Object.class);
		baseClassCache.add(String.class);
		baseClassCache.add(Class.class);
		baseClassCache.add(Date.class);
		baseClassCache.add(Enum.class);
		
		for(Class<?> primitiveType: primitiveTypeNameSet.keySet()){
			primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
		}
		
		registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class,
				Float[].class, Integer[].class, Long[].class, Short[].class);
		registerCommonClasses(Number.class, Number[].class, String.class, String[].class,
				Object.class, Object[].class, Class.class, Class[].class);
		registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class,
				Error.class, StackTraceElement.class, StackTraceElement[].class);
		
	}

	/**
	 * Register the given common classes with the ClassUtils cache.
	 */
	private static void registerCommonClasses(Class<?>... commonClasses) {
		for (Class<?> clazz : commonClasses) {
			commonClassCache.put(clazz.getName(), clazz);
		}
	}
	
	/**
	 * 判断类型是不是 Java 的原始数据类
	 *
	 * @param type
	 * @return
	 */
	public static boolean isPrimitiveType(Class<?> type){
		return primitiveTypeNameSet.containsKey(type);
	}
	
	/**
	 * 原始数据的类
	 *
	 * @param type
	 * @return
	 */
	public static boolean isPrimitiveWrapperType(Class<?> type){
		return primitiveWrapperTypeNameSet.contains(type);
	}

	/**
	 * 是否为常用类，如字符串，数值类型，Object 等
	 *
	 * @param type
	 * @return
	 */
	public static boolean isBaseType(Class<?> type){
		return isPrimitiveType(type) || isPrimitiveWrapperType(type) || baseClassCache.contains(type);
	}
	
	/**
	 * 常用类组成的数组类型
	 *
	 * @param type
	 * @return
	 */
	public static boolean isBaseArrayType(Class<?> type){
		return (type.isArray() && commonClassCache.containsKey(type));
	}
	

	/**
	 * 判断 t 是否为 parent 的子类， 或者实现 parent 接口。
	 * 
	 * 如果 t 或 parent 为 null，都返回 false
	 * 
	 * @param t
	 * @param parent
	 * @return
	 */
	public static boolean isInheritance(Class<?> t, Class<?> parent) {
		if(t == null || parent == null)
			return false;
		return parent.isAssignableFrom(t);
	}
	
	/**
	 * 判断某个类是否实现某个接口，但不会判断其父类是否实现这个接口。如果要做判断，可以使用  isInheritance 方法。
	 *
	 * @param clazz
	 * @param intf   接口
	 * @return
	 */
	public static boolean isImplements(Class<?> clazz, Class<?> intf) {
		if(clazz == null || intf == null)
			return false;
		
		return Stream.of(clazz.getInterfaces()).anyMatch(inter->inter.equals(intf));
	}
	
	/**
	 * 判断某个对象是否存在某注解
	 *
	 * @param o
	 * @param annotationClass
	 * @return
	 */
	public static boolean isAnnotationPresent(Object o, Class<? extends Annotation> annotationClass){
		return o.getClass().isAnnotationPresent(annotationClass);
	}
	
	/**
	 * 判断某个类是否存在某注解
	 * 
	 * @param source
	 * @param annotationClass
	 * @return
	 */
	public static boolean isAnnotationPresent(Class<?> source, Class<? extends Annotation> annotationClass){
		return source.isAnnotationPresent(annotationClass);
	}
	

	/**
	 * 获取当前默认的 Class Loader
	 * 
	 * @return
	 */
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back to system class loader...
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
		}
		return cl;
	}
	
	/**
	 * 判断类能否创建实例
	 * 
	 * @param clazz
	 * @return
	 */
	public static boolean canCreateInstance(Class<?> clazz){
		return clazz != null && !clazz.isAnnotation() && 
				!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers());
	}
}
